#ifndef _NE_MIDI_EVENT_H_
#define _NE_MIDI_EVENT_H_

#include <neinit.h>

namespace ne
{
    enum MIDIEventType
    {
        MIDI_NOTE_OFF         = 0x80,
        MIDI_NOTE_ON          = 0x90,
        MIDI_NOTE_PRESSURE    = 0xA0,
        MIDI_CONTROLLER       = 0xB0,
        MIDI_INSTRUMENT       = 0xC0,
        MIDI_CHANNEL_PRESSURE = 0xD0,
        MIDI_PITCH_BEND       = 0xE0,
        MIDI_SYSTEM           = 0xF0,
        MIDI_TIME_CODE        = 0xF1,
        MIDI_SONG_POSITION    = 0xF2,
        MIDI_SONG_SELECT      = 0xF3,
        // 0xF4-0xF5
        MIDI_TUNE_REQUEST     = 0xF6,
        MIDI_END_OF_EXCLUSIVE = 0xF7,
        MIDI_CLOCK            = 0xF8,
        // 0xF9
        MIDI_START            = 0xFA,
        MIDI_CONTINUE         = 0xFB,
        MIDI_STOP             = 0xFC,
        MIDI_ACTIVE_SENSE     = 0xFE,
        MIDI_META             = 0xFF
    };

    class NEAPI MIDINote
    {
        public:
            byte channel;
            byte pitch;
            byte velocity;
            byte releaseVelocity;
            double absoluteTicks;
            real duration;
    };

    typedef std::list<MIDINote*> MIDINoteList;
    typedef MIDINoteList::iterator MIDINoteListIterator;
    typedef MIDINoteList::const_iterator MIDINoteListConstIterator;

    class NEAPI MIDIEvent
    {
        public:
            MIDIEvent(const byte type,
                      const double a=0,
                      const real r=0)
                : mType(type),
                  absoluteTicks(a),
                  relatedTicks(r)
            {
            }

            byte getType() const
            {
                return mType;
            }

            virtual MIDIEvent* clone() const
            {
                return new MIDIEvent(mType, absoluteTicks, relatedTicks);
            }

            virtual ~MIDIEvent()
            {
            }

        protected:
            byte mType;

        public:
            double absoluteTicks;
            real relatedTicks;
    };

    class NEAPI MIDIChannelEvent : public MIDIEvent
    {
        public:
            MIDIChannelEvent(const byte type,
                             const byte c=0,
                             const byte p1=0,
                             const byte p2=0,
                             const double a=0,
                             const real r=0)
                : MIDIEvent(type, a, r),
                  channel(c),
                  parameter1(p1),
                  parameter2(p2)
            {
            }

            virtual MIDIEvent* clone() const
            {
                return new MIDIChannelEvent(mType, absoluteTicks, relatedTicks,
                                            channel, parameter1, parameter2);
            }

            virtual ~MIDIChannelEvent()
            {
            }

        public:
            byte channel;
            byte parameter1;
            byte parameter2;
    };

    typedef std::list<MIDIEvent*> MIDIEventList;
    typedef MIDIEventList::iterator MIDIEventListIterator;
    typedef MIDIEventList::const_iterator MIDIEventListConstIterator;
}

#endif
